/*
 * ﻿Copyright (C) 2011-2012 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.aspectjutil.dynamicagent;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.newmainsoftech.aspectjutil.dynamicagent.DynamicAspectJWeaverAgent;

/**
 * This class is just code holder, in order to take advantage of IDE's content assist and 
 * other features for coding beanshell script being used in ant file of this project.
 * The code here better be either ones demanded before Maven's test phase (so no need to say why not being 
 * able to move to source folder) or ones not suitable to put into any of test classes. Otherwise, such 
 * code should be moved to suitable test class and beanshell script in ant file should refer the yielded 
 * test class in the test output directory. <br />  
 * Coding note: Beanshell does not handle Generic and Annotation.
 * 
 * @author <a href="mailto:artymt@gmail.com">Arata Y.</a>
 */
public class ForBeanshell {
	// For beanshell script at declar_DynamicAspectJWeaverAgent_name_property_target Ant target ---
	public static final String MavenProjectReferenceId = "maven.project";
		public static String getMavenprojectreferenceid() {
			return MavenProjectReferenceId;
		}
	/**
	 * Set name of {@link DynamicAspectJWeaverAgent} class to Maven property. 
	 * Called from beanshell script at declar_DynamicAspectJWeaverAgent_name_property_target Ant target. 
	 * 
	 * @param propertyName
	 * @param antProject
	 * @throws Throwable
	 */
	public void setMavenPropertyForDynamicAspectJWeaverAgentName( 
			final String propertyName, final Object antProject) 
	throws Throwable {
		Method getReferenceMethod = 
		antProject.getClass().getMethod( "getReference", new Class<?>[]{ String.class});
			getReferenceMethod.setAccessible( true);
		Object mavenProject 
		= getReferenceMethod.invoke( antProject, ForBeanshell.getMavenprojectreferenceid());
		
		Method getPropertiesMethod 
		= mavenProject.getClass().getMethod( "getProperties", (Class<?>[])null);
			getPropertiesMethod.setAccessible( true);
		Properties properties 
		= (Properties)(getPropertiesMethod.invoke(mavenProject, (Object[])null));
		properties.setProperty( propertyName, DynamicAspectJWeaverAgent.class.getName());
	}
	// --------------------------------------------------------------------------------------------
		
	/**
	 * Moves {@link TestAgentMainClass} and {@link TestAgentPremainClass} class files out of 
	 * test class directory to temp folder. 
	 * This need to be executed in Maven's process-test-classes phase because this is about 
	 * avoiding for those classes to be at class path and be loaded for testing 
	 * {@link DynamicAspectJWeaverAgent}.
	 * 
	 * Used at beanshell script in move_test_agent_classes_to_temp_dir_target Ant target of 
	 * maven-antrun.ant.xml Ant file. The move_test_agent_classes_to_temp_dir_target Ant target 
	 * was used to be used with tests using jmockit test framework, but such tests are any longer 
	 * used since re-developed with Mockito.
	 * 
	 * @deprecated   
	 */
	public void move_test_agent_classes_to_temp_dir_target() throws Exception {
		// Departing directory setup --------------------------------------------------------------
		File projectRootDir = (new File( ".")).getAbsoluteFile();
		File testClassDir = new File( projectRootDir, "target" + File.separator + "test-classes");
			if ( !testClassDir.exists()) {
				throw new RuntimeException( 
						String.format(
								"Could not detect test class directory at %1$s",
								new Object[]{ testClassDir.getPath()}
								)
						);
			}
		File testAgentPackageSourceDir 
		= new File( 
				testClassDir, 
				TestAgentMainClass.class.getPackage().getName().replace( ".", File.separator));
		// ----------------------------------------------------------------------------------------
		
		// Destination directory setup ------------------------------------------------------------
		File destRootDir 
		= new File( DynamicAspectJWeaverAgentTest_byJmockitTest.getTestWeaverJarDestRootDirPath());
			if ( !destRootDir.exists()) destRootDir.mkdirs();
		File testAgentPackageDestDir
		= new File( 
				destRootDir, 
				TestAgentMainClass.class.getPackage().getName().replace( ".", File.separator));
			if ( !testAgentPackageDestDir.exists()) {
				testAgentPackageDestDir.mkdirs();
			}
		// ----------------------------------------------------------------------------------------
			
		FilenameFilter filenameFilter
		= new FilenameFilter() {
//			@Override	beanshell doesn't seem to be able to handle annotation
			public boolean accept( File dir, String name) {
				if ( name.endsWith( 
						TestAgentMainClass.class.getSimpleName() + ".class")
						|| name.endsWith( 
								TestAgentPremainClass.class.getSimpleName() + ".class")
						) 
				{
					return true;
				}
				return false;
			}};
		File[] testAgentClassFileArray = testAgentPackageSourceDir.listFiles( filenameFilter);
			for( File testAgentClassSourceFile : testAgentClassFileArray) {
				FileInputStream fileInputStream = new FileInputStream( testAgentClassSourceFile);
				BufferedInputStream bufferedInputStream = new BufferedInputStream( fileInputStream);
				File testAgentClassDestFile 
				= new File( testAgentPackageDestDir, testAgentClassSourceFile.getName());
				FileOutputStream fileOutputStream = new FileOutputStream( testAgentClassDestFile);
				BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( fileOutputStream);
				for( int count = bufferedInputStream.read(); count > -1; count = bufferedInputStream.read()) {
					bufferedOutputStream.write( count);
				} // for
				bufferedOutputStream.flush();
				bufferedOutputStream.close();
				bufferedInputStream.close();
				
				testAgentClassSourceFile.delete();
			} // for
			
		// Verifications --------------------------------------------------------------------------
		File testAgentMainClassDestFile 
		= new File( testAgentPackageDestDir, TestAgentMainClass.class.getSimpleName() + ".class");
		File testAgentPremainClassDestFile 
		= new File( testAgentPackageDestDir, TestAgentPremainClass.class.getSimpleName() + ".class");
			if ( !testAgentMainClassDestFile.exists() || !testAgentPremainClassDestFile.exists()) {
				throw new RuntimeException(
						String.format(
								"Failed to copy the following test agent file(s) from %1$s directory " 
								+ "to %2$s directory: %n%3$c%4$s%n%3$c%5$s",
								new Object[]{ 
										testAgentPackageSourceDir.getAbsolutePath(),
										testAgentPackageDestDir.getAbsolutePath(),
										'\t',
										(testAgentMainClassDestFile.exists() 
												? "" : testAgentMainClassDestFile.getName()),
										(testAgentPremainClassDestFile.exists() 
												? "" : testAgentPremainClassDestFile.getName())
										}
								)
						);
			}
			
		File testAgentMainClassOriginalFile 
		= new File( testAgentPackageSourceDir, TestAgentMainClass.class.getSimpleName() + ".class");
		File testAgentPremainClassOriginalFile 
		= new File( testAgentPackageSourceDir, TestAgentPremainClass.class.getSimpleName() + ".class");
			if ( testAgentMainClassOriginalFile.exists() || testAgentPremainClassOriginalFile.exists()) {
				throw new RuntimeException(
						String.format(
								"Failed to delete the following test agent file(s) in %1$s directory: " 
								+ "%n%2$c%3$s%n%2$c%4$s",
								new Object[]{ 
										testAgentPackageSourceDir.getAbsolutePath(),
										'\t',
										(!testAgentMainClassOriginalFile.exists() 
												? "" : testAgentMainClassOriginalFile.getName()),
										(!testAgentPremainClassOriginalFile.exists() 
												? "" : testAgentPremainClassOriginalFile.getName())
										}
								)
						);
			}
		// ----------------------------------------------------------------------------------------
	}
}
